package ua.kpi.ipsa.expert.api.client;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.rmi.RemoteException;
import java.util.List;

import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter.DefaultHighlightPainter;

import ua.kpi.ipsa.expert.api.net.ConsoleException;
import ua.kpi.ipsa.expert.api.net.PlagiarismHypo;
import ua.kpi.ipsa.expert.api.net.SourceFile;

public class Hypo {
	private static final String[] TITLES = new String[] { "Code1", "Code2",
			"%", "Agree", "Disagree" };

	private class HypoTableModel extends AbstractTableModel {

		@Override
		public String getColumnName(int column) {
			return TITLES[column];
		}

		@Override
		public int getRowCount() {
			return hypos.size();
		}

		@Override
		public int getColumnCount() {
			return TITLES.length;
		}

		@Override
		public Object getValueAt(int row, int col) {
			PlagiarismHypo h = hypos.get(row);
			return col == 0 ? getPath(h.code1)
					: col == 1 ? getPath(h.code2)
							: col == 2 ? String.format("%.1f%%",
									hypos.get(row).veracity * 100)
									: col == 3 ? h.userOpinion == PlagiarismHypo.USER_AGREEZ
											: h.userOpinion == PlagiarismHypo.USER_DISAGREEZ;
		}

		@Override
		public boolean isCellEditable(int row, int column) {
			return column == 3 || column == 4;
		}

		@Override
		public void setValueAt(Object value, int row, int col) {
			boolean v = (boolean) value;
			int u = col == 3 ? PlagiarismHypo.USER_AGREEZ
					: PlagiarismHypo.USER_DISAGREEZ;
			PlagiarismHypo h = hypos.get(row);
			if (v)
				h.userOpinion = u;
			else if (h.userOpinion == u)
				h.userOpinion = PlagiarismHypo.NO_INFO;
			try {
				m.getConsole().postUserAgreement(h.hypoPK, h.userOpinion);
			} catch (RemoteException | ConsoleException e) {
				error(e);
				return;
			}
			fireTableRowsUpdated(row, row);
		}

		@Override
		public Class<?> getColumnClass(int columnIndex) {
			return columnIndex == 3 || columnIndex == 4 ? Boolean.class
					: Object.class;
		}
	}

	private static String getPath(SourceFile code) {
		if (code == null)
			return "";
		StringBuilder sb = new StringBuilder();
		for (String s : code.path) {
			sb.append("/").append(s);
		}
		return sb + "";
	}

	private ClientFrameManager m;
	private JFrame parent;
	private JFrame f;
	private JTable table;
	private JScrollPane tableScroll;
	private JButton browseBtn;
	private JPanel listPanel;
	private JTextArea code1;
	private JScrollPane code1Scroll;
	private JTextArea code2;
	private JScrollPane code2Scroll;
	private JButton nextBtn;
	private JButton prevBtn;
	private JSplitPane codeSplit;
	private JPanel diffPanel;
	private JSplitPane split;
	private JButton backBtn;
	private final DefaultHighlightPainter painter = new DefaultHighlightPainter(
			new Color(0x40FF80));
	private List<PlagiarismHypo> hypos;

	public Hypo(ClientFrameManager m, JFrame parent, int codePortionID,
			int algorithmID) {
		this.m = m;
		this.parent = parent;
		try {
			hypos = m.getConsole().getPortionScore(codePortionID, algorithmID);
		} catch (RemoteException | ConsoleException e) {
			error(e);
			return;
		}
		f = m.createFrame();
		doLayout();
		f.setVisible(true);
	}

	private void doLayout() {
		// creation code
		table = new JTable(new HypoTableModel());
		tableScroll = new JScrollPane(table);
		browseBtn = new JButton("Browse second code portion");
		listPanel = new JPanel();
		code1 = new JTextArea(20, 15);
		code1Scroll = new JScrollPane(code1);
		code2 = new JTextArea(20, 15);
		code2Scroll = new JScrollPane(code2);
		nextBtn = new JButton("Next difference");
		prevBtn = new JButton("Prev difference");
		codeSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
				code1Scroll, code2Scroll);
		diffPanel = new JPanel();
		split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, listPanel,
				diffPanel);
		backBtn = new JButton("Back");

		// properties code
		table.setAutoCreateRowSorter(true);
		browseDiff();
		code1.setEditable(false);
		code2.setEditable(false);

		// listeners code
		table.getSelectionModel().addListSelectionListener(
				new ListSelectionListener() {

					@Override
					public void valueChanged(ListSelectionEvent e) {
						browseDiff();
					}
				});
		browseBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				browseCode();
			}
		});

		nextBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				nextDiff();
			}
		});

		prevBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				prevDiff();
			}
		});

		backBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				exit();
			}
		});

		// layout code
		GroupLayout listG = new GroupLayout(listPanel);
		listPanel.setLayout(listG);
		listG.setAutoCreateGaps(true);
		listG.setHorizontalGroup(listG.createParallelGroup()
				.addComponent(tableScroll).addComponent(browseBtn));
		listG.setVerticalGroup(listG.createSequentialGroup()
				.addComponent(tableScroll).addComponent(browseBtn));

		GroupLayout diffG = new GroupLayout(diffPanel);
		diffPanel.setLayout(diffG);
		diffG.setAutoCreateGaps(true);
		diffG.setHorizontalGroup(diffG
				.createParallelGroup()
				.addComponent(codeSplit)
				.addGroup(
						diffG.createSequentialGroup().addComponent(nextBtn)
								.addComponent(prevBtn)));
		diffG.setVerticalGroup(diffG
				.createSequentialGroup()
				.addComponent(codeSplit)
				.addGroup(
						diffG.createParallelGroup().addComponent(nextBtn)
								.addComponent(prevBtn)));

		GroupLayout g = new GroupLayout(f.getContentPane());
		f.setLayout(g);
		g.setAutoCreateContainerGaps(true);
		g.setAutoCreateGaps(true);
		g.setHorizontalGroup(g.createParallelGroup().addComponent(split)
				.addComponent(backBtn));
		g.setVerticalGroup(g.createSequentialGroup().addComponent(split)
				.addComponent(backBtn));

		// frame code
		f.setTitle("Hypo");
		f.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		f.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				exit();
			}
		});

		f.pack();
		f.setLocationRelativeTo(null);
	}

	private void nextDiff() {
		moveDiff(1);
	}

	private void prevDiff() {
		moveDiff(-1);
	}

	private void moveDiff(int dir) {
		int row = table.getSelectedRow();
		if (row == -1)
			return;
		PlagiarismHypo h = hypos.get(row);
		if (h.code1 == null && h.code2 == null)
			return;
		for (int i = row + dir; 0 <= i && i < hypos.size(); i += dir) {
			if (hypos.get(i).code1 == h.code1 && hypos.get(i).code2 == h.code2) {
				table.getSelectionModel().setSelectionInterval(i, i);
				return;
			}
		}
	}

	private void browseDiff() {
		int row = table.getSelectedRow();
		browseBtn.setEnabled(row != -1 && hypos.get(row).codePortion2PK != 0);
		if (row == -1)
			return;
		PlagiarismHypo h = hypos.get(row);
		code1.setText(h.code1 == null ? "" : h.code1.body);
		code2.setText(h.code2 == null ? "" : h.code2.body);
		try {
			code1.getHighlighter().removeAllHighlights();
			if (h.code1 != null) {
				code1.getHighlighter().addHighlight(h.code1PlagStart,
						h.code1PlagEnd, painter);
				code1.setCaretPosition(h.code1PlagStart);
			}
			code2.getHighlighter().removeAllHighlights();
			if (h.code2 != null) {
				code2.getHighlighter().addHighlight(h.code2PlagStart,
						h.code2PlagEnd, painter);
				code2.setCaretPosition(h.code2PlagStart);
			}
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}

	private void browseCode() {
		int row = table.getSelectedRow();
		if (row == -1)
			return;
		int code2 = hypos.get(row).codePortion2PK;
		if (code2 == 0)
			return;
		f.setVisible(false);
		new BrowseSource(m, f, code2);
	}

	private void exit() {
		m.disposeFrame(f);
		parent.setVisible(true);
	}

	private void error(Throwable e) {
		JOptionPane.showMessageDialog(null, "Connection error", "Error",
				JOptionPane.ERROR_MESSAGE);
		e.printStackTrace();
		m.ceaseOperations();
	}
}
